using System;
using System.Collections;
using System.Configuration;
using System.Xml;
using System.Xml.XPath;

namespace DotNetScriptEngine
{
	//These three classes are custom Configuration Section Handlers used to read
	//the three custom sections in the config file

	#region Referenced Assembly Handler
	/// <summary>
	/// Custom config file reader for the list of referenced assemblies
	/// </summary>
	internal class DotNetScriptAssemblySectionHandler : IConfigurationSectionHandler
	{
		internal static ArrayList assemblies;

		internal DotNetScriptAssemblySectionHandler()
		{
			assemblies = new ArrayList();
		}
			
		/// <summary>
		/// This is the only meathod defined in IConfigurationSectionHandler.  The XmlNode
		/// parm passes in one section at a time.  So if you have 4 referenced assemblies,
		/// Create() will be called 4 times, once for each referenced assembly
		/// </summary>
		public object Create(object parent, object configContext, System.Xml.XmlNode section)
		{
			assemblies.Add(section.Attributes["path"].Value);			
			return assemblies;
		}
	}
	#endregion Referenced Assembly Handler



	
	#region Supported Language Handler
	/// <summary>
	/// Custom config file reader for the list of supported languages
	/// </summary>
	internal class DotNetScriptLanguageSectionHandler : IConfigurationSectionHandler
	{		
		internal static Hashtable assemblies;

		internal DotNetScriptLanguageSectionHandler()
		{
			assemblies = new Hashtable();
		}
	
		/// <summary>
		/// This is the only meathod defined in IConfigurationSectionHandler.  The XmlNode
		/// parm passes in one section at a time.  So if you have 4 languages defined,
		/// Create() will be called 4 times, once for each language
		/// </summary>
		public object Create(object parent, object configContext, System.Xml.XmlNode section)
		{			
			string languageName = section.Attributes["name"].Value;
			string assembly = section.Attributes["assembly"].Value;
			string codeProviderName = section.Attributes["codeProviderName"].Value;
			assemblies.Add(languageName, new DotNetLanguage(languageName, assembly, codeProviderName));

			return assemblies;
		}
	}

	/// <summary>
	/// This class holds information for one supported language
	/// languageName is the actual name that you enter in the dnml file or the config file
	/// assembly is the full path the the assembly file that contains the language specific code provider class
	/// codeProvider name is the full name, including namespaces, of the code provider class
	/// </summary>
	internal class DotNetLanguage
	{
		internal readonly string languageName = string.Empty;
		internal readonly string assembly = string.Empty;
		internal readonly string codeProviderName = string.Empty;

		internal DotNetLanguage(string languageName, string assembly, string codeProviderName)
		{
			this.languageName = languageName;
			this.assembly = assembly;
			this.codeProviderName = codeProviderName;
		}
	}
	#endregion Supported Language Handler




	#region User Preferences Handler
	/// <summary>
	/// Custom config file reader for the user preferences
	/// </summary>
	internal class DotNetScriptUserPreferencesSectionHandler : IConfigurationSectionHandler
	{				
		internal DotNetScriptUserPreferencesSectionHandler()
		{
		}

		/// <summary>
		/// This is the only meathod defined in IConfigurationSectionHandler. 
		/// </summary>
		public object Create(object parent, object configContext, System.Xml.XmlNode section)
		{			
			string defaultLanguage = section.Attributes["defaultLanguage"].Value;
			string entryPoint = section.Attributes["entryPoint"].Value;
			bool waitForUserAction = bool.Parse(section.Attributes["waitForUserAction"].Value);			
			
			return new UserPreferences(defaultLanguage, waitForUserAction, entryPoint);
		}
	}

	/// <summary>
	/// This class defines the user preferences
	/// defaultLanguage is the language the script will be compiled for.  If the dnml file does not
	/// define the language, then the value defined in the config file will be used by the script engine.
	/// waitForUserAction defines if the console window will remain open when the script file is
	/// finished running.  If the dnml file does not define this, then the value from the config file 
	/// will be used by the script engine.
	/// entryPoint is the method that will be called by the script engine.  If the dnml file does not
	/// define the entry point, then the one defined in the config file will be used by the script engine.
	/// </summary>
	internal struct UserPreferences
	{
		internal string defaultLanguage;
		internal bool waitForUserAction;
		internal string entryPoint;

		internal UserPreferences(string defaultLanguage, bool waitForUserAction, string entryPoint)
		{
			this.defaultLanguage = defaultLanguage;
			this.waitForUserAction = waitForUserAction;
			this.entryPoint = entryPoint;
		}
	}
	#endregion User Preferences Handler

}
